/*
 * $Author: isan.wong@gmail.com $
 * $Date: 2011-07-29 01:03:06 +0000 (Fri, 29 Jul 2011) $
 * $Rev: 13 $
 * $URL: http://capitalbio-smd.googlecode.com/svn/src/com/capitalbio/smd/gui/MainFrame.java $
 */

package com.capitalbio.smd.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.biojava.bio.symbol.Symbol;
import org.biojava.bio.symbol.SymbolList;
import com.capitalbio.hla.gui.ByExtentionFileChooser;
import com.capitalbio.hla.gui.ByExtentionFileFilter;
import com.capitalbio.smd.base.Project;
import com.capitalbio.smd.base.Sample;
import com.capitalbio.smd.base.StdGene;
import com.capitalbio.smd.base.Util;
import com.capitalbio.smd.base.Variation;

/**
 * 主程序
 * 
 * @author Wang Lei
 */
public class MainFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	protected Log log = LogFactory.getLog(this.getClass());

	public static final String APPNAME = "CapitalBio-SMD";

	private File lastDir;
	
	private Action actionImport;
	private Action actionRemove;
	private Action actionRemoveAll;
	private Action actionExit;
	private Action actionAnalyze;
	private Action actionAnalyzeAll;
	private Action actionOptimize;
	private Action actionOptimizeAll;
	private Action actionReportAll;
	private Action actionExportLog;
	private Action actionSettings;
	private Action actionHelp;
	private Action actionAbout;

	private ProjectPane projectPane;
	private JMenuBar menuBar;
	private JToolBar toolBar;
	private StatusBar statusBar;
	private ProgressDialog progressDialog;

	private Project project;
	private StdGeneComboBox stdGeneComboBox;

	public MainFrame() {
		super(APPNAME);
		setIconImage(new ImageIcon(Util.getResourceURL("icon/icon_app_16.png"))
				.getImage());

		actionImport = new ImportAction("Import...", new ImageIcon(
				Util.getResourceURL("icon/icon_import_16.png")));
		actionRemove = new RemoveAction("Remove", new ImageIcon(
				Util.getResourceURL("icon/icon_remove_16.png")));
		actionRemoveAll = new RemoveAllAction("Remove All", new ImageIcon(
				Util.getResourceURL("icon/icon_removeall_16.png")));
		actionExit = new ExitAction("Exit");
		actionAnalyzeAll = new AnalyzeAllAction("Analyze All", new ImageIcon(
				Util.getResourceURL("icon/icon_analysisall_16.png")));
		actionAnalyze = new AnalyzeAction("Analyze", new ImageIcon(
				Util.getResourceURL("icon/icon_analysis_16.png")));
		actionOptimize = new OptimizeAction("Optimize", new ImageIcon(
				Util.getResourceURL("icon/icon_optimize_16.png")));
		actionOptimizeAll = new OptimizeAllAction("Optimize All",
				new ImageIcon(
						Util.getResourceURL("icon/icon_optimizeall_16.png")));
		actionReportAll = new ReportAllAction(
				Util.getText("smd.gui.action.reportAll.label"), new ImageIcon(
						Util.getResourceURL("icon/icon_reportall_16.png")));
		actionExportLog = new ExportLogAction(
				Util.getText("smd.gui.action.exportLog.label"), new ImageIcon(
						Util.getResourceURL("icon/icon_exportlog_16.png")));
		actionSettings = new SettingsAction("Settings", new ImageIcon(
				Util.getResourceURL("icon/icon_settings_16.png")));
		actionHelp = new HelpAction("Help Content");
		actionAbout = new AboutAction("About");

		// 菜单栏
		initializeMenuBar();
		setJMenuBar(menuBar);

		// 工具栏
		initializeToolBar();
		getContentPane().add(toolBar, BorderLayout.NORTH);

		// 样品列表区和样品区
		projectPane = new ProjectPane(this);
		getContentPane().add(projectPane, BorderLayout.CENTER);

		// 状态栏
		statusBar = new StatusBar();
		getContentPane().add(statusBar, BorderLayout.SOUTH);

		// 进度对话框
		progressDialog = new ProgressDialog(this);

		Project newProject = new Project();
		newProject.setProperties(new Properties(Util.getProperties()));
		setProject(newProject);
	}

	/**
	 * 生成菜单栏
	 * 
	 * @return JMenuBar 对象
	 */
	private void initializeMenuBar() {
		menuBar = new JMenuBar();
		JMenuItem item = null;

		// File 菜单
		JMenu mProject = new JMenu("File");
		mProject.setMnemonic('f');

		item = mProject.add(actionImport);
		item.setMnemonic('i');

		mProject.addSeparator();

		item = mProject.add(actionExit);
		item.setMnemonic('x');

		menuBar.add(mProject);

		// Analysis 菜单
		JMenu mAnalysis = new JMenu("Analysis");
		mAnalysis.setMnemonic('a');

		item = mAnalysis.add(actionAnalyze);
		item.setMnemonic('a');

		item = mAnalysis.add(actionAnalyzeAll);
		item.setMnemonic('n');

		//item = mAnalysis.add(actionOptimize);
		//item.setMnemonic('o');

		//item = mAnalysis.add(actionOptimizeAll);
		//item.setMnemonic('p');

		menuBar.add(mAnalysis);

		// Report 菜单
		JMenu mReport = new JMenu("Report");
		mReport.setMnemonic('r');

		item = mReport.add(actionReportAll);
		item.setMnemonic('e');

		item = mReport.add(actionExportLog);
		item.setMnemonic('l');

		menuBar.add(mReport);

		// Tools 菜单
		//JMenu mTools = new JMenu("Tools");
		//mTools.setMnemonic('t');
		//item = mTools.add(actionSettings);
		//item.setMnemonic('s');
		//menuBar.add(mTools);

		// Help 菜单
		JMenu mHelp = new JMenu("Help");
		mHelp.setMnemonic('h');

		//item = mHelp.add(actionHelp);
		//item.setMnemonic('c');

		item = mHelp.add(actionAbout);
		item.setMnemonic('a');

		menuBar.add(mHelp);
	}

	/**
	 * 生成工具栏
	 * 
	 * @return JToolBar 对象
	 */
	private void initializeToolBar() {
		toolBar = new JToolBar();
		toolBar.setFloatable(false);

		// File 工具面板
		JButton button = toolBar.add(actionImport);
		button.setToolTipText("Import");
		button.setText("Import");
		button.setVerticalTextPosition(SwingConstants.CENTER);
		button.setHorizontalTextPosition(SwingConstants.RIGHT);

		// Sample 工具面板
		toolBar.add(new JToolBar.Separator());

		button = toolBar.add(actionRemove);
		button.setToolTipText("Remove");
		button.setText("Remove");
		button.setVerticalTextPosition(SwingConstants.CENTER);
		button.setHorizontalTextPosition(SwingConstants.RIGHT);

		button = toolBar.add(actionRemoveAll);
		button.setToolTipText("Remove All");

		// Analysis 工具面板
		toolBar.add(new JToolBar.Separator());

		button = toolBar.add(actionAnalyze);
		button.setToolTipText("Analyze");
		button.setText("Analyze");
		button.setVerticalTextPosition(SwingConstants.CENTER);
		button.setHorizontalTextPosition(SwingConstants.RIGHT);

		button = toolBar.add(actionAnalyzeAll);
		button.setToolTipText("Analyze All");

		//toolBar.add(new JToolBar.Separator());

		//button = toolBar.add(actionOptimize);
		//button.setToolTipText("Optimize");
		//button.setText("Optimize");
		//button.setVerticalTextPosition(SwingConstants.CENTER);
		//button.setHorizontalTextPosition(SwingConstants.RIGHT);

		//button = toolBar.add(actionOptimizeAll);
		//button.setToolTipText("Optimize All");

		// Report 工具面板
		toolBar.add(new JToolBar.Separator());

		button = toolBar.add(actionReportAll);
		button.setToolTipText(Util.getText("smd.gui.action.reportAll.tip"));
		button.setText(Util.getText("smd.gui.action.reportAll.label"));
		button.setVerticalTextPosition(SwingConstants.CENTER);
		button.setHorizontalTextPosition(SwingConstants.RIGHT);

		button = toolBar.add(actionExportLog);
		button.setToolTipText(Util.getText("smd.gui.action.exportLog.tip"));
		button.setText(Util.getText("smd.gui.action.exportLog.label"));
		button.setVerticalTextPosition(SwingConstants.CENTER);
		button.setHorizontalTextPosition(SwingConstants.RIGHT);

		// Standard gene combobox
		toolBar.add(new JToolBar.Separator());

		stdGeneComboBox = new StdGeneComboBox();

		JPanel functionPane = new JPanel(new BorderLayout());
		functionPane.setOpaque(false);
		functionPane.add(stdGeneComboBox, BorderLayout.WEST);

		toolBar.add(functionPane);
		
		for (Component component : toolBar.getComponents()) {
			if (component instanceof JButton) {
				JButton cButton = (JButton) component;
				cButton.setVerticalTextPosition(SwingConstants.CENTER);
				cButton.setHorizontalTextPosition(SwingConstants.RIGHT);
				cButton.setMargin(new Insets(6, 6, 6, 6));
			}
		}
	}

	/**
	 * 获取项目面板
	 * 
	 * @return 项目面板
	 */
	public ProjectPane getProjectPane() {
		return projectPane;
	}

	/**
	 * 设置项目面板
	 * 
	 * @param projectPane
	 *            项目面板
	 */
	public void setProjectPane(ProjectPane projectPane) {
		this.projectPane = projectPane;
	}

	/**
	 * 获取工具栏
	 * 
	 * @return 工具栏
	 */
	public JToolBar getToolBar() {
		return toolBar;
	}

	/**
	 * 设置工具栏
	 * 
	 * @param toolBar
	 *            工具栏
	 */
	public void setToolBar(JToolBar toolBar) {
		this.toolBar = toolBar;
	}

	/**
	 * 获取状态栏
	 * 
	 * @return 状态栏
	 */
	public StatusBar getStatusBar() {
		return statusBar;
	}

	/**
	 * 设置状态栏
	 * 
	 * @param statusBar
	 *            状态栏
	 */
	public void setStatusBar(StatusBar statusBar) {
		this.statusBar = statusBar;
	}

	/**
	 * 获取项目
	 * 
	 * @return 项目对象
	 */
	public Project getProject() {
		return project;
	}

	/**
	 * 设置项目
	 * 
	 * @param project
	 */
	public void setProject(Project project) {
		// setTitle(project.getName());
		updateProject(project);
	}

	public void updateProject(Project project) {
		this.project = project;
		//fireTableDataChanged();
		projectPane.updateProject(project);
	}
	
	@Override
	public void setTitle(String title) {
		super.setTitle(title + " - " + APPNAME);
	}

	/**
	 * 关于, 显示软件相关信息
	 */
	private class AboutAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public AboutAction(String name) {
			super(name);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			AboutDialog aboutDialog = new AboutDialog(MainFrame.this);
			aboutDialog.setVisible(true);
		}
	}

	/**
	 * 分析当前选择的样品
	 */
	private class AnalyzeAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public AnalyzeAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			final Sample sample = projectPane.getSamplePane().getSample();
			if (sample != null) {
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						progressDialog.getProgressBar().setMaximum(1);
						progressDialog.getProgressBar().setValue(0);
						progressDialog.setVisible(true);
					}
				});
				Thread analyze = new Thread() {
					public void run() {
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressLabel()
										.setText(
												"Analyzing " + sample.getName()
														+ "...");
								progressDialog.getProgressBar().setValue(1);
							}
						});
						try {
							sample.analyze((StdGene) stdGeneComboBox
									.getSelectedItem());
						} catch (Exception e) {
							JOptionPane.showMessageDialog(
									MainFrame.this,
									"Error occured." + e.getMessage(),
									"Error",
									JOptionPane.ERROR_MESSAGE);
						}
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressBar().setValue(1);
								if (sample == projectPane.getSamplePane()
										.getSample()) {
									projectPane.getSamplePane().setSample(sample);
								}
								progressDialog.setVisible(false);
							}
						});
					}
				};
				analyze.start();
			}
		}
	}

	/**
	 * 分析全部样品
	 */
	private class AnalyzeAllAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public AnalyzeAllAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			final List<Sample> samples = project.getSamples();
			log.debug((samples == null ? "0" : samples.size()) + " samples found.");
			
			if (samples != null && samples.size() > 0) {
				Thread analyzeAll = new Thread() {
					public void run() {
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressBar().setMaximum(
										samples.size());
								progressDialog.getProgressBar().setValue(0);
								progressDialog.setVisible(true);
							}
						});
						for (int i = 0; i < samples.size(); i++) {
							final Sample sample = samples.get(i);
							final int j = i + 1;
							if (sample != null) {
								SwingUtilities.invokeLater(new Runnable() {
									public void run() {
										progressDialog
												.getProgressLabel()
												.setText(
														"Analyzing "
																+ sample.getName()
																+ "...");
										progressDialog.getProgressBar()
												.setValue(j);
									}
								});
								try {
									sample.analyze((StdGene) stdGeneComboBox
										.getSelectedItem());
								}
								catch (final Exception e) {
									JOptionPane.showMessageDialog(
											MainFrame.this,
											"Error occured." + e.getMessage(),
											"Error",
											JOptionPane.ERROR_MESSAGE);
								}
								if (sample == projectPane.getSamplePane()
										.getSample()) {
									SwingUtilities.invokeLater(new Runnable() {
										public void run() {
											projectPane.getSamplePane()
													.setSample(sample);
										}
									});
								}
							}
						}
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.setVisible(false);
							}
						});
					}
				};
				analyzeAll.start();
			}
		}
	}

	/**
	 * 优化当前选择的样品
	 */
	private class OptimizeAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public OptimizeAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			final Sample sample = projectPane.getSamplePane().getSample();
			if (sample != null) {
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						progressDialog.getProgressBar().setMaximum(1);
						progressDialog.getProgressBar().setValue(0);
						progressDialog.setVisible(true);
					}
				});
				Thread optimize = new Thread() {
					public void run() {
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressLabel().setText(
										"Optimizing " + sample.getName()
												+ "...");
								progressDialog.getProgressBar().setValue(1);
							}
						});
						try {
							sample.optimize((StdGene) stdGeneComboBox
									.getSelectedItem());
						} catch (final Exception e) {
							JOptionPane.showMessageDialog(
									MainFrame.this,
									"Error occured." + e.getMessage(),
									"Error",
									JOptionPane.ERROR_MESSAGE);
						}
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressBar().setValue(1);
								if (sample == projectPane.getSamplePane()
										.getSample()) {
									projectPane.getSamplePane().setSample(
											sample);
								}
								progressDialog.setVisible(false);
							}
						});
					}
				};
				optimize.start();
			}
		}
	}

	/**
	 * 优化全部样品
	 */
	private class OptimizeAllAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public OptimizeAllAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			final List<Sample> samples = project.getSamples();
			if (samples != null && samples.size() > 0) {
				Thread optimizeAll = new Thread() {
					public void run() {
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressBar().setMaximum(
										samples.size());
								progressDialog.getProgressBar().setValue(0);
								progressDialog.setVisible(true);
							}
						});
						for (int i = 0; i < samples.size(); i++) {
							final Sample sample = samples.get(i);
							final int j = i + 1;
							if (sample != null) {
								SwingUtilities.invokeLater(new Runnable() {
									public void run() {
										progressDialog
												.getProgressLabel()
												.setText(
														"Optimizing "
																+ sample.getName()
																+ "...");
										progressDialog.getProgressBar()
												.setValue(j);
									}
								});
								try {
									sample.optimize((StdGene) stdGeneComboBox
											.getSelectedItem());
								} catch (final Exception e) {
									JOptionPane.showMessageDialog(
											MainFrame.this,
											"Error occured." + e.getMessage(),
											"Error",
											JOptionPane.ERROR_MESSAGE);
								}
								if (sample == projectPane.getSamplePane()
										.getSample()) {
									SwingUtilities.invokeLater(new Runnable() {
										public void run() {
											projectPane.getSamplePane()
													.setSample(sample);
										}
									});
								}
							}
						}
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.setVisible(false);
							}
						});
					}
				};
				optimizeAll.start();
			}
		}
	}

	/**
	 * 导出全部样品的报告
	 */
	private class ReportAllAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public ReportAllAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {

			ByExtentionFileChooser fileChooser = new ByExtentionFileChooser(lastDir, new String[] {"xls"}, "Microsoft Office Excel 2003 File (*.xls)");
			fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
			fileChooser.setMultiSelectionEnabled(true);

			if (fileChooser.showSaveDialog(MainFrame.this) != JFileChooser.APPROVE_OPTION) {
				return;
			}

			final File reportFile = fileChooser.getSelectedFile();
			if (reportFile == null) {
				return;
			}
			
			lastDir = reportFile.getParentFile();
			
			final boolean isVerbal = false;
			final List<Sample> samples = project.getSamples();
			if (samples != null && samples.size() > 0) {
				Thread reportAll = new Thread() {
					public void run() {
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressBar().setMaximum(
										samples.size());
								progressDialog.getProgressBar().setValue(0);
								progressDialog.setVisible(true);
							}
						});

						Workbook workbook = new HSSFWorkbook();
						Sheet sheet = workbook.createSheet("Report");

						// styles
						CellStyle sectionStyle = workbook.createCellStyle();
						org.apache.poi.ss.usermodel.Font sectionFont = workbook
								.createFont();
						// titleFont.setBoldweight(org.apache.poi.ss.usermodel.Font.BOLDWEIGHT_BOLD);
						sectionFont.setColor(HSSFColor.RED.index);
						sectionStyle.setFont(sectionFont);
						sectionStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);
						sectionStyle
								.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);

						CellStyle titleStyle = workbook.createCellStyle();
						org.apache.poi.ss.usermodel.Font titleFont = workbook
								.createFont();
						titleFont.setColor(HSSFColor.BLUE.index);
						titleStyle.setFont(titleFont);
						titleStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);
						titleStyle
								.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);

						CellStyle contentStyle = workbook.createCellStyle();
						org.apache.poi.ss.usermodel.Font contentFont = workbook
								.createFont();
						contentFont.setColor(HSSFColor.BLACK.index);
						contentStyle.setFont(contentFont);
						contentStyle.setWrapText(true);
						contentStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);
						contentStyle
								.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);

						CellStyle sequenceStyle = workbook.createCellStyle();
						org.apache.poi.ss.usermodel.Font sequenceFont = workbook
								.createFont();
						sequenceFont.setFontName("Courier New");
						sequenceFont.setColor(HSSFColor.BLACK.index);
						sequenceStyle.setFont(sequenceFont);
						sequenceStyle.setWrapText(true);
						sequenceStyle.setAlignment(XSSFCellStyle.ALIGN_LEFT);
						sequenceStyle
								.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);

						int currentRow = 1;
						Row row = null;
						Cell cell = null;
						for (int i = 0; i < samples.size(); i++) {

							final Sample sample = samples.get(i);
							final int j = i + 1;
							if (sample != null) {
								SwingUtilities.invokeLater(new Runnable() {
									public void run() {
										progressDialog
												.getProgressLabel()
												.setText(
														"Exporting report of "
																+ sample.getName()
																+ "...");
										progressDialog.getProgressBar()
												.setValue(j);
									}
								});

								List<Variation> variations = sample.getResult()
										.getVariations();

								int extraLineCount = 0;
								if (isVerbal) {
									extraLineCount = 3;
								}

								if (variations.size() > 0) {
									sheet.addMergedRegion(new CellRangeAddress(
											currentRow, // first row (0-based)
											currentRow + variations.size() - 1, // last
																				// row
																				// (0-based)
											1, // first column (0-based)
											1 // last column (0-based)
									));

									sheet.addMergedRegion(new CellRangeAddress(
											currentRow, // first row (0-based)
											currentRow + variations.size()
													+ extraLineCount - 1, // last
																			// row
																			// (0-based)
											0, // first column (0-based)
											0 // last column (0-based)
									));

									for (int k = 0; k < variations.size(); k++) {
										StringBuilder variationsBuilder = new StringBuilder();
										variationsBuilder.append(variations
												.get(k).toString());
										variationsBuilder
												.append(variations.get(k)
														.isHomozygous() ? " [Hom]"
														: " [Het]");

										row = sheet.createRow(currentRow++);
										cell = row.createCell(2);
										cell.setCellValue(variationsBuilder
												.toString());
										cell.setCellStyle(sequenceStyle);

										if (k == 0) {
											cell = row.createCell(1);
											cell.setCellValue("Mutations");
											cell.setCellStyle(titleStyle);

											cell = row.createCell(0);
											cell.setCellValue(sample.getName());
											cell.setCellStyle(sectionStyle);
										}
									}
								} else {

									sheet.addMergedRegion(new CellRangeAddress(
											currentRow, // first row (0-based)
											currentRow + extraLineCount, // last
																			// row
																			// (0-based)
											0, // first column (0-based)
											0 // last column (0-based)
									));

									row = sheet.createRow(currentRow++);
									cell = row.createCell(2);
									cell.setCellValue("N/A");
									cell.setCellStyle(sequenceStyle);

									cell = row.createCell(1);
									cell.setCellValue("Mutations");
									cell.setCellStyle(titleStyle);

									cell = row.createCell(0);
									cell.setCellValue(sample.getName());
									cell.setCellStyle(sectionStyle);
								}

								if (isVerbal) {
									row = sheet.createRow(currentRow++);
									cell = row.createCell(1);
									cell.setCellValue("Reference");
									cell.setCellStyle(titleStyle);

									cell = row.createCell(2);
									cell.setCellValue(Util.formatSequence2(
											sample.getResult().getSeq0()
													.seqString().toUpperCase(),
											80, 10));
									cell.setCellStyle(sequenceStyle);

									row = sheet.createRow(currentRow++);
									cell = row.createCell(1);
									cell.setCellValue("Chromosome 1");
									cell.setCellStyle(titleStyle);

									cell = row.createCell(2);
									cell.setCellValue(Util.formatSequence2(
											sample.getResult().getSeq1()
													.seqString().toUpperCase(),
											80, 10));
									cell.setCellStyle(sequenceStyle);

									row = sheet.createRow(currentRow++);
									cell = row.createCell(1);
									cell.setCellValue("Chromosome 2");
									cell.setCellStyle(titleStyle);

									cell = row.createCell(2);
									cell.setCellValue(Util.formatSequence2(
											sample.getResult().getSeq2()
													.seqString().toUpperCase(),
											80, 10));
									cell.setCellStyle(sequenceStyle);
								}

							}

							try {
								Thread.sleep(30);
							} catch (InterruptedException e) {
								log.error(e);
							}
						}

						for (int n = 0; n < 4; n++) {
							sheet.autoSizeColumn(n);
						}

						// add picture data to this workbook.
						try {
							URL titleURL = Util.getResourceURL("report_title_"
									+ Util.getProperty("smd.program.languange")
									+ "_"
									+ Util.getProperty("smd.program.country")
									+ ".png");

							InputStream is = new FileInputStream(
									titleURL.getFile());
							byte[] bytes = IOUtils.toByteArray(is);
							int pictureIdx = workbook.addPicture(bytes,
									Workbook.PICTURE_TYPE_JPEG);
							is.close();

							BufferedImage bi = ImageIO.read(titleURL);
							int titleHeight = bi.getHeight();
							sheet.createRow(0).setHeightInPoints(
									(float) (titleHeight * 0.75));

							// Create the drawing patriarch. This is the top
							// level container for all shapes.
							Drawing drawing = sheet.createDrawingPatriarch();

							// add a picture shape
							ClientAnchor anchor = workbook.getCreationHelper()
									.createClientAnchor();
							// set top-left corner of the picture,
							// subsequent call of Picture#resize() will operate
							// relative to it
							anchor.setCol1(0);
							anchor.setRow1(0);
							Picture picture = drawing.createPicture(anchor,
									pictureIdx);

							// auto-size picture relative to its top-left corner
							picture.resize();

						} catch (FileNotFoundException e) {
							log.error(e);
						} catch (IOException e) {
							log.error(e);
						}

						try {
							FileOutputStream reportOutputStream;
							reportOutputStream = new FileOutputStream(
									reportFile);
							workbook.write(reportOutputStream);
							reportOutputStream.flush();
							reportOutputStream.close();
						} catch (FileNotFoundException e) {
							log.error(e);
						} catch (IOException e) {
							log.error(e);
						}

						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.setVisible(false);
								JOptionPane.showMessageDialog(MainFrame.this,
										"Report file exported successfully.\nFile saved at "
												+ reportFile.getAbsolutePath(),
										"Information",
										JOptionPane.INFORMATION_MESSAGE);
							}
						});
					}
				};
				reportAll.start();
			}
		}
	}

	/**
	 * 导出日志
	 */
	private class ExportLogAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public ExportLogAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {

			ByExtentionFileChooser fileChooser = new ByExtentionFileChooser(lastDir, new String[] {"txt", "log"}, "Log File (*.log, *.txt)");
			fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
			fileChooser.setMultiSelectionEnabled(false);

			if (fileChooser.showSaveDialog(MainFrame.this) != JFileChooser.APPROVE_OPTION) {
				return;
			}

			final File logFile = fileChooser.getSelectedFile();
			if (logFile == null) {
				return;
			}
			lastDir = logFile.getParentFile();

			final List<Sample> samples = project.getSamples();
			if (samples != null && samples.size() > 0) {
				Thread exportLog = new Thread() {
					public void run() {
						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressBar().setMaximum(
										samples.size());
								progressDialog.getProgressBar().setValue(0);
								progressDialog.setVisible(true);
							}
						});

						try {
							FileWriter logWriter = new FileWriter(logFile);
							logWriter.write("CapitalBio SMD Log\n------------------\n\n");
							
							Date now = new Date();
							logWriter.write(String.format("%tF", now) + " " + String.format("%tT", now) + "\n");

							for (int i = 0; i < samples.size(); i++) {

								final Sample sample = samples.get(i);
								final int j = i + 1;
								if (sample != null) {
									SwingUtilities.invokeLater(new Runnable() {
										public void run() {
											progressDialog
													.getProgressLabel()
													.setText(
															"Exporting log of "
																	+ sample.getName()
																	+ "...");
											progressDialog.getProgressBar()
													.setValue(j);
										}
									});

									logWriter.write("------------------\n");
									logWriter.write("Sample:\n"
											+ sample.getName() + "\n\n");
									logWriter.write("Chromatogram File:\n"
											+ sample.getChromat().getChromatogramFile()
													.getAbsolutePath() + "\n\n");

									try {
										SymbolList symbolList = sample.getChromat().getSymbolList();
										int symbolListLength = symbolList.length();
										logWriter.write("IUBMB sequence:\n");
										logWriter.write(Util.formatSequence1(
												symbolList.seqString()
														.toUpperCase(), 60)+ "\n\n");

										logWriter.write("Changes:\nLocation\tFrom\tTo\n");
										SymbolList resultSymbolList = sample
												.getResult().getSymbolList();
										for (int k = 1; k <= symbolListLength; k++) {
											Symbol symbol1 = symbolList.symbolAt(k);
											Symbol symbol2 = resultSymbolList
													.symbolAt(k);
											if (symbol1 != symbol2) {
												logWriter
														.write(k
																+ "\t"
																+ Util.getSymbolToken(symbol1)
																+ "\t"
																+ Util.getSymbolToken(symbol2)
																+ "\n");
											}
										}
										logWriter.write("\n");

										logWriter.write("Edited sequence:\n");
										logWriter.write(Util.formatSequence1(
												resultSymbolList.seqString()
														.toUpperCase(), 60)
												+ "\n\n");

										logWriter
												.write("Corresponding gene sequence:\n");
										logWriter.write(Util.formatSequence1(sample
												.getResult().getSeq0().seqString()
												.toUpperCase(), 60)
												+ "\n\n");
										logWriter.write("Chromosome 1 sequence:\n");
										logWriter.write(Util.formatSequence1(sample
												.getResult().getSeq1().seqString()
												.toUpperCase(), 60)
												+ "\n\n");
										logWriter.write("Chromosome 2 sequence:\n");
										logWriter.write(Util.formatSequence1(sample
												.getResult().getSeq2().seqString()
												.toUpperCase(), 60)
												+ "\n\n");

										logWriter.write("Alignment:\n");
										logWriter.write(Util.formatAlignment(60,
												sample.getResult().getSeq0(),
												sample.getResult().getSeq1(),
												sample.getResult().getSeq2()));

										logWriter.write("Mutations:\nDescription\tHom/Het\n");
										List<Variation> variations = sample
												.getResult().getVariations();
										for (int k = 0; k < variations.size(); k++) {
											logWriter
													.write(variations.get(k)
															.toString() + "\t"
															+ (variations.get(k)
																	.isHomozygous() ? "Hom"
																	: "Het") + "\n");

										}

										logWriter.write("\n");
									} catch (final Exception e) {
										JOptionPane.showMessageDialog(MainFrame.this,
												"Error occured while setting sample.\n" + e.getMessage(),
												"Error Occured", JOptionPane.ERROR_MESSAGE);
									}
								}
							}

							logWriter.flush();
							logWriter.close();
						} catch (IOException e) {
							log.error(e);
						}

						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.setVisible(false);
								JOptionPane.showMessageDialog(MainFrame.this,
										"Log file exported successfully.\nFile saved at "
												+ logFile.getAbsolutePath(),
										"Information",
										JOptionPane.INFORMATION_MESSAGE);
							}
						});
					}
				};
				exportLog.start();
			}
		}
	}

	/**
	 * 退出, 退出软件
	 */
	private class ExitAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public ExitAction(String name) {
			super(name);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			System.exit(0);
		}
	}

	/**
	 * 帮助
	 */
	private class HelpAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public HelpAction(String name) {
			super(name);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			HelpDialog helpDialog = new HelpDialog(MainFrame.this);
			helpDialog.setVisible(true);
		}
	}

	/**
	 * 导入, 导入文件到当前项目
	 */
	public class ImportAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public ImportAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent actionEvent) {

			ByExtentionFileChooser fileChooser = new ByExtentionFileChooser(lastDir, new String[] {"scf"}, "SCF Chromatogram File");
			fileChooser.addChoosableFileFilter(new ByExtentionFileFilter(new String[] {"ab1", "abi"}, "ABI Chromatogram File"));
			fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
			fileChooser.setMultiSelectionEnabled(true);

			if (fileChooser.showSaveDialog(MainFrame.this) != JFileChooser.APPROVE_OPTION) {
				return;
			}

			final File[] files = fileChooser.getSelectedFiles();
			if (files == null || files.length == 0) {
				return;
			}

			lastDir = files[0].getParentFile();
			log.debug("用户导入了" + files.length + "个文件.");

			Thread analyze = new Thread() {
				public void run() {

					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							progressDialog.getProgressBar().setMaximum(
									files.length);
							progressDialog.setVisible(true);
						}
					});

					for (int i = 0; i < files.length; i++) {
						final int j = i + 1;
						final File file = files[i];

						SwingUtilities.invokeLater(new Runnable() {
							public void run() {
								progressDialog.getProgressLabel().setText(
										"Importing " + file.getName() + "...");
								progressDialog.getProgressBar().setValue(j);
							}
						});

						try {
							final Sample sample = new Sample(file, project.getProperties());
							sample.setProperties(new Properties(project.getProperties()));
							
							SwingUtilities.invokeLater(new Runnable() {
								public void run() {
									projectPane.getSampleListPane()
											.getSampleListData().add(sample);
									projectPane
											.getSampleListPane()
											.getSampleListTable()
											.tableChanged(
													new TableModelEvent(
															projectPane
																	.getSampleListPane()
																	.getSampleListData(),
															projectPane
																	.getSampleListPane()
																	.getSampleListData()
																	.getRowCount(),
															projectPane
																	.getSampleListPane()
																	.getSampleListData()
																	.getRowCount(),
															TableModelEvent.ALL_COLUMNS,
															TableModelEvent.INSERT));
								}
							});
						} catch (final Throwable e) {
							log.error(e);
							JOptionPane.showMessageDialog(MainFrame.this,
									"Error occured while creating sample.\n" + e.getMessage(),
									"Error Occured", JOptionPane.ERROR_MESSAGE);
						}
					}

					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
							progressDialog.setVisible(false);
						}
					});
				}
			};
			analyze.start();
		}
	}

	/**
	 * 移除样品
	 */
	public class RemoveAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public RemoveAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {

			project.setStatusChanged(true);
			
			JTable sampleListTable = projectPane.getSampleListPane().getSampleListTable();
			SampleListTableData sampleListTableData = projectPane.getSampleListPane().getSampleListData();
			int[] indexes = sampleListTable.getSelectedRows();
			
			if (JOptionPane.showConfirmDialog(MainFrame.this, "Selected samples will be removed, please confirm your operation.", "Remove Sample", JOptionPane.YES_NO_OPTION) != JOptionPane.OK_OPTION) {
				return;
			}
			
			sampleListTableData.removeIndexes(indexes);
			projectPane.showLoadingPane();
		}
	}
	
	/**
	 * 移除全部样品
	 */
	public class RemoveAllAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public RemoveAllAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {

			project.setStatusChanged(true);
			
			if (JOptionPane.showConfirmDialog(MainFrame.this, "All samples will be removed, please confirm your operation.", "Remove All Samples", JOptionPane.YES_NO_OPTION) != JOptionPane.OK_OPTION) {
				return;
			}
			
			SampleListTableData sampleListTableData = projectPane.getSampleListPane().getSampleListData();
			if (sampleListTableData.removeAll()) {
				projectPane.showLoadingPane();
			}
		}
	}

	/**
	 * 设置, 打开设置面板
	 */
	public class SettingsAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		public SettingsAction(String name, Icon icon) {
			super(name, icon);
		}

		@Override
		public void actionPerformed(ActionEvent evt) {
			SettingsDialog settingsDialog = new SettingsDialog(MainFrame.this);
			settingsDialog.setVisible(true);
		}
	}
}
